package org.example.ioc.context;

import org.example.ioc.annotation.Component;
import org.example.ioc.annotation.ComponentScan;
import org.example.ioc.annotation.Service;

import java.io.File;
import java.net.URL;
import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;
import java.util.Set;
import java.util.HashSet;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;

public class ApplicationContext {
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>();
    private final Map<String, Class<?>> beanDefinitions = new ConcurrentHashMap<>();
    private final Set<String> basePackages = new HashSet<>();

    public ApplicationContext(Class<?> configClass) {
        // 解析配置类上的ComponentScan注解
        ComponentScan componentScan = configClass.getAnnotation(ComponentScan.class);
        if (componentScan != null) {
            basePackages.addAll(Arrays.asList(componentScan.basePackages()));
        }

        // 扫描并注册Bean
        scanAndRegisterBeans();
        
        // 初始化所有单例Bean
        instantiateSingletons();
    }

    private void scanAndRegisterBeans() {
        for (String basePackage : basePackages) {
            scanPackage(basePackage);
        }
    }

    private void scanPackage(String basePackage) {
        try {
            String packagePath = basePackage.replace(".", "/");
            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            Enumeration<URL> resources = classLoader.getResources(packagePath);
            
            while (resources.hasMoreElements()) {
                URL resource = resources.nextElement();
                String protocol = resource.getProtocol();
                
                if ("file".equals(protocol)) {
                    // 处理文件协议
                    String filePath = URLDecoder.decode(resource.getFile(), StandardCharsets.UTF_8);
                    scanClassesFromFile(new File(filePath), basePackage);
                } else if ("jar".equals(protocol)) {
                    // 处理jar协议
                    scanClassesFromJar(resource, basePackage);
                }
            }
        } catch (Exception e) {
            System.err.println("扫描包时出错: " + basePackage + ", 错误: " + e.getMessage());
        }
    }

    private void scanClassesFromFile(File directory, String packageName) {
        if (!directory.exists() || !directory.isDirectory()) {
            return;
        }
        
        File[] files = directory.listFiles();
        if (files != null) {
            for (File file : files) {
                if (file.isDirectory()) {
                    // 递归扫描子目录
                    scanClassesFromFile(file, packageName + "." + file.getName());
                } else if (file.getName().endsWith(".class")) {
                    // 处理class文件
                    String className = packageName + "." + file.getName().substring(0, file.getName().length() - 6);
                    processClass(className);
                }
            }
        }
    }

    private void scanClassesFromJar(URL jarUrl, String packageName) {
        try {
            String jarPath = jarUrl.getPath();
            if (jarPath.startsWith("file:")) {
                jarPath = jarPath.substring(5, jarPath.indexOf("!"));
                jarPath = URLDecoder.decode(jarPath, StandardCharsets.UTF_8);
            }
            
            try (JarFile jarFile = new JarFile(jarPath)) {
                Enumeration<JarEntry> entries = jarFile.entries();
                String packagePath = packageName.replace(".", "/") + "/";
                
                while (entries.hasMoreElements()) {
                    JarEntry entry = entries.nextElement();
                    String entryName = entry.getName();
                    
                    if (entryName.startsWith(packagePath) && entryName.endsWith(".class")) {
                        String className = entryName.substring(0, entryName.length() - 6).replace("/", ".");
                        processClass(className);
                    }
                }
            }
        } catch (Exception e) {
            System.err.println("扫描JAR包时出错: " + jarUrl + ", 错误: " + e.getMessage());
        }
    }

    private void processClass(String className) {
        try {
            Class<?> clazz = Class.forName(className);
            // 检查是否有Component注解
            if (clazz.isAnnotationPresent(Component.class) || clazz.isAnnotationPresent(Service.class)) {
                Component component = clazz.getAnnotation(Component.class);
                Service service = clazz.getAnnotation(Service.class);
                
                String beanName = "";
                if (service != null && !service.value().isEmpty()) {
                    beanName = service.value();
                } else if (component != null && !component.value().isEmpty()) {
                    beanName = component.value();
                }
                
                if (beanName.isEmpty()) {
                    // 如果没有指定名称，使用类名首字母小写作为Bean名称
                    beanName = clazz.getSimpleName();
                    beanName = beanName.substring(0, 1).toLowerCase() + beanName.substring(1);
                }
                beanDefinitions.put(beanName, clazz);
                System.out.println("发现Bean: " + beanName + " -> " + className);
            }
        } catch (ClassNotFoundException e) {
            System.err.println("无法加载类: " + className);
        } catch (NoClassDefFoundError e) {
            System.err.println("找不到类定义: " + className);
        }
    }

    private void instantiateSingletons() {
        for (Map.Entry<String, Class<?>> entry : beanDefinitions.entrySet()) {
            String beanName = entry.getKey();
            Class<?> beanClass = entry.getValue();
            try {
                Object instance = beanClass.getDeclaredConstructor().newInstance();
                singletonObjects.put(beanName, instance);
                System.out.println("成功创建Bean: " + beanName + " 类型: " + beanClass.getName());
            } catch (Exception e) {
                System.err.println("创建Bean失败: " + beanName + " 错误: " + e.getMessage());
                e.printStackTrace();
            }
        }
    }

    public Object getBean(String beanName) {
        return singletonObjects.get(beanName);
    }

    public <T> T getBean(Class<T> requiredType) {
        for (Object bean : singletonObjects.values()) {
            if (requiredType.isInstance(bean)) {
                return (T) bean;
            }
        }
        return null;
    }

    public <T> T getBean(String beanName, Class<T> requiredType) {
        Object bean = singletonObjects.get(beanName);
        if (bean != null && requiredType.isInstance(bean)) {
            return (T) bean;
        }
        System.err.println("未找到Bean: " + beanName + " 类型: " + requiredType.getName());
        System.err.println("可用的Beans: " + singletonObjects.keySet());
        return null;
    }
    
    // 添加调试方法
    public void printRegisteredBeans() {
        System.out.println("注册的Bean定义:");
        for (Map.Entry<String, Class<?>> entry : beanDefinitions.entrySet()) {
            System.out.println("  " + entry.getKey() + " -> " + entry.getValue().getName());
        }
        
        System.out.println("实例化的Beans:");
        for (Map.Entry<String, Object> entry : singletonObjects.entrySet()) {
            System.out.println("  " + entry.getKey() + " -> " + entry.getValue().getClass().getName());
        }
    }
}
